package com.lanluo.service.concurrent.semaphore;

import java.util.concurrent.Semaphore;
import java.util.concurrent.locks.ReentrantLock;

/**
 *
 * 资源的多副本的并发访问控制-Semaphore
 * 引用自：https://blog.csdn.net/zbc1090549839/article/details/53389602
 *
 * 信号量的作用：1.假如有5个资源，有10个线程需要获得
 *               2.信号量控制同一时间只有5个线程进入来获取这5个资源，剩下的5个线程进入休眠
 *               3.当其中一个线程执行完毕释放这个资源，释放信号量，剩下的线程中的一个执行释放的资源
 * @author
 * @date 2018-09-03-9:45
 */
public class ResourceManager {
    private final Semaphore semaphore;
    //资源的数量
    private boolean[] resourceArray = new boolean[5];
    private final ReentrantLock lock;

    public ResourceManager() {
        this.semaphore = new Semaphore(5);
        this.lock = new ReentrantLock(true);
        for (int i = 0; i < 5; i++) {
            resourceArray[i] = true;
        }
    }

    /**
     * 资源使用
     * @param userid
     */
    public void userResource(int userid) {
        try {
            semaphore.acquire(); //保证同一时间只有固定数量的线程进入来获取资源，信号量-1
            int id = getResourceId(); //固定数量的线程争夺固定数量的资源
            System.out.println("用户："+userid+"正在使用资源，资源id："+id+"\n");
            System.out.println("******************************************************使用中:"+userid);
            Thread.sleep(userid * 1000 + 3000);
            resourceArray[id] = true;
        } catch (InterruptedException e) {
            System.out.println(e.getMessage());
        } finally {
            System.out.println("userid:"+userid+"使用资源完毕");
            System.out.println("******************************************************使用完毕:"+userid);
            semaphore.release(); //执行完毕，信号量+1
        }

    }

    /**
     * 固定的线程获取固定资源，通过同步锁来避免争夺同一资源
     * @return
     */
    public int getResourceId() {
        int id = -1;
        lock.lock();
        for (int i = 0; i < 5; i++) {
            if(resourceArray[i]) {
                resourceArray[i] = false;
                id = i;
                break;
            }
        }
        lock.unlock();
        return id;
    }

}